package net.cyndeline.entitySystem

import net.cyndeline.entitySystem.defaultImpl.Aspect
import language.postfixOps

/**
 * Contains functionality used by any class that can handle events, and
 * must be extended by any event-handling systems.
 * 
 * @param event The type of event this system handles.
 * @param aspect filter that determines which entities this handler is 
 * 				 interested in, based on their components. Must contain at least
 *      		 one component class in the getAll or getSome sets.
 */
abstract class AbstractEventHandlerSystem(aspect: Aspect, eventList: Class[_ <: Event]*) extends EventHandlerSystem with ComponentSystem with EventReceiver {
  if ((aspect.all isEmpty) && (aspect.some isEmpty)) {
    throw new IllegalArgumentException("The provided aspect did not contain " +
    		"any specified component classes. This event handler will not be " +
    		"eligible for incoming messages.")
  }
  
  private var listensForEvents = true
  
  def events: List[Class[_ <: Event]] = eventList.toList
  
  /**
   * Process the event. Unlike the original framework, every event
   * will be sent to this method for processing.
   */
  def onEvent(event: Event, entity: EntityRef): Unit
  
  /**
   * Override this to add additional logic to perform when the system
   * starts up. Does nothing by default.
   */
  def initialise = {}
  
  /**
   * Override this to add additional logic to perform when the system
   * shuts down. Does nothing by default.
   */
  def shutdown = {}
  
  /**
   * Stop this system from receiving events.
   */
  def disable {
    listensForEvents = false
  }
  
  /**
   * Begin receiving events again.
   */
  def enable {
    listensForEvents = true
  }
  
  /**
   * Current listener status of this system.
   */
  def enabled = listensForEvents
  
  /**
   * Checks if this handler is interested in an entity based on its components.
   * @param entity Entity that has received a message.
   * @param True if the entitys component set matches this handlers aspect filter.
   */
  def isValidFor(entity: EntityRef): Boolean = {    
    val classes = for (component: Component <- entity.iterateComponents) yield component.getClass
    val classSet: Set[Class[_ <: Component]] = Set(classes.toArray: _*)

    if (!aspect.all.subsetOf(classSet)) {
      false
      
    } else if ((aspect.some nonEmpty) && ((classSet & aspect.some) isEmpty)){
      false
      
    } else if ((aspect.exclud nonEmpty) && ((classSet & aspect.exclud) nonEmpty)) {
      false
      
    } else {
      true
    }
  }
}